﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Media;

namespace Jewelnoid
{
    class LevelSurvival : Level
    {
        public double time;
        public List<List<int>> previousBlocksMatrix;
        public List<TetrisPiece> usedTetrisPieceList;
        public int secondsToNextLine;
        public int pieceCount;

        public override void start()
        {
            base.start();

            this.time = 0;
            this.secondsToNextLine = 4;
            this.pieceCount = 0;
            this.previousBlocksMatrix = new List<List<int>>();
            this.usedTetrisPieceList = new List<TetrisPiece>();

            for (int i = 0; i < 4; i++)  //4 linhas são o suficiente
            {
                List<int> line = new List<int>();

                for (int j = 0; j < this.blockManager.maxColumn; j++)
                {
                    line.Add(0);
                }

                this.previousBlocksMatrix.Add(line);
            }

            generateLine();

            fillFirstLine();

            this.blockManager.blocksStartPosition = windowSize.X - ((this.blockManager.blockTexture.Width + 5) * this.blockManager.maxColumn);

            this.lvlInterface.lifes = 1;
            this.lvlInterface.update();

            SoundManager.playMusic("tetris", true);
        }

        public override void terminate()
        {
            base.terminate();

            SoundManager.stopMusic();
        }

        public override void update(GameTime gameTime)
        {
            if (gameTime.TotalGameTime.TotalSeconds - this.time >= this.secondsToNextLine && ballReleased)
            {
                this.time = gameTime.TotalGameTime.TotalSeconds;
                generateLine();

                for (int i = this.blockManager.maxLine - 2; i >= 0; i--)
                {
                    for (int j = this.blockManager.maxColumn - 1; j >= 0; j--)
                    {
                        this.blockManager.blocksMatrix[i + 1][j] = this.blockManager.blocksMatrix[i][j];

                        if (i == 0)
                        {
                            this.blockManager.blocksMatrix[i][j] = this.previousBlocksMatrix[3][j];
                        }
                    }
                }

                updatePreviousBlocksMatrix();

                if (this.lvlInterface.score.scoreNumber >= 5000 && this.lvlInterface.score.scoreNumber < 15000)
                {
                    this.secondsToNextLine = 2;
                }
                else if (this.lvlInterface.score.scoreNumber >= 15000)
                {
                    this.secondsToNextLine = 1;
                }
            }
            else if (!ballReleased)
            {
                this.time = gameTime.TotalGameTime.TotalSeconds;
            }

            base.update(gameTime);

            if (lvlInterface.lifes == 0)
            {
                SceneManager.setScene(new Menu());
            }
        }

        private void fillFirstLine()
        {
            for (int j = 0; j < this.blockManager.maxColumn; j++)
            {
                this.blockManager.blocksMatrix[0][j] = this.previousBlocksMatrix[3][j];
            }

            updatePreviousBlocksMatrix();
        }

        private void updatePreviousBlocksMatrix()
        {
            for (int i = 2; i >= 0; i--)
            {
                for (int k = 0; k < this.blockManager.maxColumn; k++)
                {
                    this.previousBlocksMatrix[i + 1][k] = this.previousBlocksMatrix[i][k];
                }
            }

            for (int l = 0; l < this.blockManager.maxColumn; l++) //Zera a primeira linha
            {
                this.previousBlocksMatrix[0][l] = 0;
            }
        }

        /// <summary>
        ///     Tenho certeza que em pouco tempo não farei a menor idéia mais de como isso funciona
        /// </summary>
        private void generateLine()
        {
            TetrisPiece lastPiece = null;

            for (int j = 0; j < this.blockManager.maxColumn; j++)
            {
                if (this.previousBlocksMatrix[3][j] == 0)
                {
                    usedTetrisPieceList = new List<TetrisPiece>();
                    TetrisPiece onePiece = TetrisPiece.generateGenericPiece(j); //One Piece!! \o/

                    if (lastPiece != null && onePiece.type == lastPiece.type)
                    {
                        onePiece = getNextPiece();
                    }

                    while (usedTetrisPieceList.Count < 7)
                    {
                        if (isTetrisPieceFit(onePiece, 3, j))
                        {
                            lastPiece = onePiece;

                            for (int i = 0; i < 4; i++)
                            {
                                for (int k = 0; k < 4; k++)
                                {
                                    try
                                    {
                                        if (this.previousBlocksMatrix[i][k + j] == 0)
                                        {
                                            this.previousBlocksMatrix[i][k + j] = onePiece.matrix[i][k];
                                        }
                                    }
                                    catch (ArgumentOutOfRangeException e)
                                    {
                                        //Chegou no final da tabela
                                    }
                                }
                            }

                            break;
                        }
                        else
                        {
                            if (!containsTetrisPiece(onePiece, usedTetrisPieceList))
                            {
                                usedTetrisPieceList.Add(onePiece);
                            }
                            
                            onePiece = getNextPiece();

                            if (lastPiece != null && usedTetrisPieceList.Count < 6 && onePiece.type == lastPiece.type)
                            {
                                onePiece = getNextPiece();
                            }
                        }   
                    }
                }
            }
        }

        private Boolean containsTetrisPiece(TetrisPiece onePiece, List<TetrisPiece> pieces)
        {
            for (int i = 0; i < pieces.Count; i++)
            {
                if (pieces[i].type == onePiece.type)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        ///     Retorna a próxima peça que Não está no usedTetrisPieceList.
        /// </summary>
        /// <returns></returns>
        private TetrisPiece getNextPiece()
        {
            Array types = Enum.GetValues(typeof(TetrisPiece.Type));

            for (int i = 0; i < types.Length; i++)
            {
                TetrisPiece piece = TetrisPiece.generatePiece((TetrisPiece.Type)types.GetValue(this.pieceCount));

                this.pieceCount++;

                if (this.pieceCount == 7)
                {
                    this.pieceCount = 0;
                }

                if (!containsTetrisPiece(piece, this.usedTetrisPieceList))
                {
                    return piece;
                }
            }

            return null;
        }

        /// <summary>
        ///     Retorna Verdadeiro se a peça encaixa na Pré Matriz e a primeira posição (0,0) contém bloco da peça.
        ///     Caso contrário retorna falso.
        /// </summary>
        /// <param name="piece"></param>
        /// <param name="positionI"></param>
        /// <param name="positionJ"></param>
        /// <param name="rotation"></param>
        /// <returns></returns>
        private Boolean isTetrisPieceFit(TetrisPiece piece, int positionI, int positionJ, int rotation)
        {
            for (int k = 0; k < rotation; k++)
            {
                piece.rotate();
            }

            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (piece.matrix[3][0] == 0)
                    {
                        return false;
                    }

                    try
                    {
                        if (piece.matrix[i][j] != 0 && this.previousBlocksMatrix[i + (positionI - 3)][j + positionJ] != 0)
                        {
                            return false;
                        }
                    }
                    catch (ArgumentOutOfRangeException e)
                    {
                        //Final da matriz previousBlocksMatrix

                        if (piece.matrix[i][j] != 0)
                        {
                            return false;
                        }
                    }
                }
            }

            return true;
        }

        private Boolean isTetrisPieceFit(TetrisPiece piece, int positionI, int positionJ)
        {
            int count = 0;

            while (!isTetrisPieceFit(piece, positionI, positionJ, count) && count < 4)
            {
                count++;
            }

            return isTetrisPieceFit(piece, positionI, positionJ, 0);
        }
    }
}
